package cn.example.demo.modules.house.service.impl;

import cn.example.demo.common.db.pojo.entity.BaseEntity;
import cn.example.demo.common.model.service.ServiceResult;
import cn.example.demo.common.retrieval.PageBean;
import cn.example.demo.common.secure.annotation.DataScopeEnable;
import cn.example.demo.common.secure.context.LoginUserApi;
import cn.example.demo.common.tools.QueryServiceUtils;
import cn.example.demo.common.tools.obj.reflect.EntityUtils;
import cn.example.demo.modules.house.dto.HouseDto;
import cn.example.demo.modules.house.entity.House;
import cn.example.demo.modules.house.entity.HousingOrder;
import cn.example.demo.modules.house.entity.RecommendResult;
import cn.example.demo.modules.house.mapper.HouseMapper;
import cn.example.demo.modules.house.mapper.HousingOrderMapper;
import cn.example.demo.modules.house.service.IHouseService;
import cn.example.demo.modules.house.service.IRecommendResultService;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 描述：【房源】接口实现类
 */
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
@Service
public class HouseServiceImpl extends ServiceImpl<HouseMapper, House> implements IHouseService {
    @Autowired
    private LoginUserApi loginUserApi;
    @Resource
    private IRecommendResultService recommendResultService;
    @Resource
    private HousingOrderMapper housingOrderMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult insertHouse(HouseDto houseDto) {
        House entity = EntityUtils.entityConvert(houseDto, new House(), false);

        // 默认状态值（待审批）
        entity.setHouseStatus(1);

        if (this.save(entity)) {
            return ServiceResult.isSuccess(StrUtil.format("【房源，ID:{}】创建成功!", entity.getId()), entity);
        }

        return ServiceResult.isInternalError("【房源】创建失败，未知错误！");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult updateHouse(HouseDto houseDto) {
        House entity = this.getById(houseDto.getId());
        if (entity == null) {
            return ServiceResult.isNotFound(StrUtil.format("【房源】信息更新失败：记录不存在！ID:{}", houseDto.getId()));
        }

        entity = EntityUtils.entityConvert(houseDto, entity, true);
        if (this.updateById(entity)) {
            return ServiceResult.isSuccess(StrUtil.format("【房源，ID:{}】信息更新成功!", entity.getId()), null);
        }

        return ServiceResult.isNotModified("未知错误，【房源】信息修改失败！");
    }

    @Override
    public PageBean queryHouse(HouseDto houseDto) {
        // 当前实现类代理对象
        HouseServiceImpl proxy = (HouseServiceImpl) AopContext.currentProxy();

        Page pageResult = PageHelper.startPage(houseDto.getPageNum(), houseDto.getPageSize())
                .doSelectPage(() -> this.list(proxy.getQueryWrapper(houseDto)));

        return QueryServiceUtils.encapsulatePageBean(new PageBean<>(), pageResult);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult deleteHouse(HouseDto houseDto) {
        int rows = this.baseMapper.deleteBatchIds(houseDto.getIds());
        if (rows > 0) {
            return ServiceResult.isSuccess(StrUtil.format("操作成功，已批量删除【房源】共 {} 条记录！", rows), rows);
        }

        return ServiceResult.isNotModified("删除【房源】失败，请稍后重试！");
    }

    @Override
    public House findHouseById(String id) {
        HouseDto houseDto = new HouseDto();
        houseDto.setId(id);

        QueryWrapper wrapper = getJoinQueryWrapper(houseDto);
        // 图片状态：显示
        wrapper.eq("t2.image_status", 1);
        House house = this.baseMapper.selectOneJoinHouseImage(wrapper);

        return house;
    }

    @Override
    public List<Map<String, Object>> queryHouseAsDict(HouseDto houseDto) {
        return this.baseMapper.selectAsDictList(getQueryWrapper(houseDto));
    }

    @Override
    public ServiceResult batchUpdateStatus(HouseDto houseDto) {
        LambdaUpdateWrapper<House> wrapper = Wrappers.lambdaUpdate();
        wrapper.set(House::getHouseStatus, houseDto.getHouseStatus())
                .in(House::getId, houseDto.getIds());

        if (this.update(wrapper)) {
            return ServiceResult.isSuccess(StrUtil.format("操作成功，已批量审批【房源】共 {} 条记录！", houseDto.getIds().size()), houseDto.getIds().size());
        }

        return ServiceResult.isNotModified("审批【房源】失败，请稍后重试！");
    }

    @Override
    public PageBean searchHouseList(HouseDto houseDto) {
        // TODO-lzx 过滤【待审批和审批不通过】的列表
        houseDto.setHouseStatusList(Arrays.asList(1, 3));
        Page pageResult = PageHelper.startPage(houseDto.getPageNum(), houseDto.getPageSize())
                .doSelectPage(() -> this.baseMapper.selectHouseJoinHouseImage(getJoinQueryWrapper(houseDto)));
        return QueryServiceUtils.encapsulatePageBean(new PageBean<>(), pageResult);
    }

    @Override
    public PageBean recommendHouseList(HouseDto houseDto) {
        // TODO-lzx 过滤【待审批和审批不通过】的列表
        houseDto.setHouseStatusList(Arrays.asList(1, 3));
        // 查询指定用户推荐列表
        RecommendResult recommendResult = recommendResultService.queryRecommendResultByUserId(loginUserApi.getCurrentLoginUser().getUserId());
        List<String> recommendList = recommendResult != null ? JSONUtil.parseArray(recommendResult.getRecommendedIds()).toList(String.class) : null;
        if (recommendList == null) {
            return new <RecommendResult>PageBean(houseDto.getPageNum(), houseDto.getPageSize(), 0);
        }
        // 构建查询参数
        QueryWrapper<House> wrapper = Wrappers.query();
        wrapper.in("t1.id", recommendList)
                .notIn(ObjectUtil.isNotEmpty(houseDto.getHouseStatusList()), "t1.house_status", houseDto.getHouseStatusList()) // 过滤不能查询的状态码
                .apply("t1.inventory > t1.ordering")   // 过滤库存大于0的房源
                .last(StrUtil.format("ORDER BY FIELD(t1.id, '{}')", String.join("','", recommendList))); // 动态生成 ORDER BY FIELD(house_id, 'uuid1','uuid2','uuid3') 语句
        Page pageResult = PageHelper.startPage(houseDto.getPageNum(), houseDto.getPageSize())
                .doSelectPage(() -> this.baseMapper.selectHouseJoinHouseImage(wrapper));
        return QueryServiceUtils.encapsulatePageBean(new PageBean<>(), pageResult);
    }

    @Override
    public List<House> getUserHistoryHouseList(Integer userId) {
        // 查询用户历史订单，找到历史房源
        List<String> housingId = housingOrderMapper.selectList(Wrappers.<HousingOrder>lambdaQuery().eq(BaseEntity::getCreateUser, userId).ge(HousingOrder::getOrderStatus, 2)).stream()
                .map(HousingOrder::getHouseId)
                .collect(Collectors.toList());
        if (housingId.isEmpty()) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<House> wrapper = Wrappers.lambdaQuery();
        wrapper.in(House::getId, housingId);
        return this.baseMapper.selectList(wrapper);
    }

    /**
     * 查询条件
     *
     * @param houseDto
     * @return
     */
    @DataScopeEnable
    protected LambdaQueryWrapper getQueryWrapper(HouseDto houseDto) {
        LambdaQueryWrapper<House> wrapper = Wrappers.lambdaQuery();

        wrapper
                .eq(StrUtil.isNotBlank(houseDto.getId()), House::getId, houseDto.getId())
                .like(StrUtil.isNotBlank(houseDto.getHouseTitle()), House::getHouseTitle, houseDto.getHouseTitle())
                .like(StrUtil.isNotBlank(houseDto.getRegionId()), House::getRegionId, houseDto.getRegionId())
                .like(StrUtil.isNotBlank(houseDto.getHouseType()), House::getHouseType, houseDto.getHouseType())
                .like(StrUtil.isNotBlank(houseDto.getProvide()), House::getProvide, houseDto.getProvide())
                .eq(houseDto.getDetail() != null, House::getDetail, houseDto.getDetail())
                .eq(houseDto.getCost() != null, House::getCost, houseDto.getCost())
                .eq(houseDto.getDiscount() != null, House::getDiscount, houseDto.getDiscount())
                .eq(houseDto.getHouseStatus() != null, House::getHouseStatus, houseDto.getHouseStatus())
                .eq(houseDto.getOrganizationId() != null, House::getOrganizationId, houseDto.getOrganizationId())
                .eq(houseDto.getCreateUser() != null, House::getCreateUser, houseDto.getCreateUser())
                .like(StrUtil.isNotBlank(houseDto.getCreateUserName()), House::getCreateUserName, houseDto.getCreateUserName())
                .ge(houseDto.getCreateTimeStart() != null, House::getCreateTime, houseDto.getCreateTimeStart())
                .le(houseDto.getCreateTimeEnd() != null, House::getCreateTime, houseDto.getCreateTimeEnd())
                .eq(houseDto.getUpdateUser() != null, House::getUpdateUser, houseDto.getUpdateUser())
                .like(StrUtil.isNotBlank(houseDto.getUpdateUserName()), House::getUpdateUserName, houseDto.getUpdateUserName())
                .ge(houseDto.getUpdateTimeStart() != null, House::getUpdateTime, houseDto.getUpdateTimeStart())
                .le(houseDto.getUpdateTimeEnd() != null, House::getUpdateTime, houseDto.getUpdateTimeEnd());

        return wrapper;
    }

    /**
     * 查询条件（关联查询）
     * Q
     *
     * @param houseDto
     * @return
     */
    protected QueryWrapper getJoinQueryWrapper(HouseDto houseDto) {
        QueryWrapper<House> wrapper = Wrappers.query();
        wrapper.eq(StrUtil.isNotBlank(houseDto.getId()), "t1.id", houseDto.getId())
                .like(StrUtil.isNotBlank(houseDto.getHouseTitle()), "t1.house_title", houseDto.getHouseTitle())
                .eq(StrUtil.isNotBlank(houseDto.getRegionId()), "t1.region_id", houseDto.getRegionId())
                .eq(StrUtil.isNotBlank(houseDto.getHouseType()), "t1.house_type", houseDto.getHouseType())
                .like(StrUtil.isNotBlank(houseDto.getDetailLocation()), "t1.detail_location", houseDto.getDetailLocation())
                .like(StrUtil.isNotBlank(houseDto.getProvide()), "t1.provide", houseDto.getProvide())
                .ge(houseDto.getCostStart() != null, "t1.cost", houseDto.getCostStart())
                .le(houseDto.getCostEnd() != null, "t1.cost", houseDto.getCostEnd())
                .eq(houseDto.getHouseStatus() != null, "t1.house_status", houseDto.getHouseStatus())
                // 过滤不能查询的状态码
                .notIn(ObjectUtil.isNotEmpty(houseDto.getHouseStatusList()), "t1.house_status", houseDto.getHouseStatusList())
                // 过滤库存大于0的房源
                .apply("t1.inventory > t1.ordering");
        wrapper.orderByDesc("t1.update_time");
        return wrapper;
    }
}
